<?php
namespace humhub\modules\api\controllers;

use Yii;
use humhub\modules\api\controllers\BaseController;
use humhub\modules\api\models\Login;
use humhub\modules\api\models\ApiAuth;

use humhub\modules\api\models\Registration;
//use humhub\modules\user\models\forms\Registration;

use humhub\modules\user\models\User;
use humhub\modules\user\authclient\AuthClientHelpers;
#use humhub\modules\user\models\Invite;
use humhub\modules\api\models\Invite;

/**
 * 登录, 注册, 退出登录, 手机验证
 */
class AuthController extends BaseController
{
    public $modelClass = 'humhub\modules\api\models\User';
    private $user_id = 0;

    /**
     * @inheritdoc
     */
    public function actions(){
        $actions = parent::actions();
        unset($actions['index'], $actions['view'], $actions['delete'], $actions['update'], $actions['create']);
        return $actions;
    }

    /**
     * @inheritdoc
    public function beforeAction($action){
    // Remove authClient from session - if already exists
    Yii::$app->session->remove('authClient');
    return parent::beforeAction($action);
    }
     */

    /**
     * 用户登录, 仅支持单终端, 支持邮箱和手机, token有效期默认30天.
     *
     * POST /api/auth/login
     *
     * string $username 登录名，仅支持: email / phone
     *
     * string $password 密码
     *
     * @return array token
     *
     * @exclude param integer $rememberMe 是否记住登录状态:1:Y/0:N
     */
    public function actionLogin(){
        // If user is already logged in, return true
        //if( ! Yii::$app->user->isGuest ){ //避免session开启的情况下有Login状态
        //    return array('success'=>true);
        //}

        $login = new Login();
        if( $login->load( ['Login' => Yii::$app->request->post()] ) ){
            if( $login->validate() ){
                if( ($sts = $this->onAuthSuccess($login->authClient) === true) ){
                    return $this->setToken();
                }else{
                    Yii::$app->params['res-success'] = false;
                    return $sts;
                }
            }else{
                //频率限制
                //$user = User::find()->where(['mphone' => $login->username])->orWhere(['email' => $login->username])->one();
                //if( $user ){
                //}
            }
        }
        Yii::$app->params['res-success'] = false;
        return $login->getErrors();
    }

    /**
     * 使用邮箱注册帐号
     *
     * POST /api/auth/reg
     *
     * string Password[newPassword]   密码
     *
     * string Password[newPasswordConfirm]   重复密码，值同newPassword
     *
     * string Profile[firstname]  First Name
     *
     * string Profile[lastname]   Last Name
     *
     * string User[email]      邮箱（使用邮箱注册时传值）
     *
     * string User[mphone]     手机号（使用手机号注册时传值）
     *
     * string User[username]   用户名
     *
     * string Invite[token]   验证码
     *
     * @return array token
     */
    public function actionReg(){
        if( ! isset($_POST['User']['username']) ){
            $_POST['User']['username'] = 'UNI-' . substr(time(),-5)  . rand(100,999);
        }
        $_POST['GroupUser']['group_id'] = 2; //user_group = 2[User]
        $_POST['Password']['newPasswordConfirm'] = isset($_POST['Password']['newPassword'])?$_POST['Password']['newPassword']:'';
        $_POST['save'] = 1;
        $registration = new Registration();

        $phone = '';
        if( isset(Yii::$app->request->post('User')['mphone']) && Yii::$app->request->post('User')['mphone'] ){
            $phone = Yii::$app->request->post('User')['mphone'];
            $registration->enablePhoneField = true;
        }
        if( isset(Yii::$app->request->post('User')['email']) && Yii::$app->request->post('User')['email'] ){
            $phone = Yii::$app->request->post('User')['email'];
            $registration->enableEmailField = true;
        }
        if( $phone ){
            if( isset(Yii::$app->request->post('Invite')['token']) ){
                $token = Yii::$app->request->post('Invite')['token'];
                if( ! is_numeric($token) ){
                    throw new \yii\web\BadRequestHttpException('账号或验证码无效');
                }
                //$userInvite = Invite::findOne(['email'=>$phone, 'token'=>$token]);
                $userInvite = Invite::findOne(['email'=>$phone]);
                if( $userInvite ){
                    //限制校验次数
                    if( $userInvite->cklimit >= 5 ){
                        throw new \yii\web\BadRequestHttpException('操作过于频繁，请稍后再试.');
                    }
                    if( $userInvite->token==$token ){
                        //throw new \yii\web\BadRequestHttpException('ok');
                    }else{
                        //$userInvite->cklimit += 1; // !!! 无并发能力
                        $userInvite->cklimit = new \yii\db\Expression('COALESCE(cklimit, 0) + 1');
                        $userInvite->update();
                        throw new \yii\web\BadRequestHttpException('账号或验证码无效');
                    }
                }else{
                    throw new \yii\web\BadRequestHttpException('账号或验证码无效');
                }
            }else{
                throw new \yii\web\BadRequestHttpException('账号或验证码无效');
            }
        }else{
            throw new \yii\web\BadRequestHttpException('不是有效的手机号或邮箱');
        }
        $registration->enableUserApproval = false;

        if( $registration->submitted('save') ){
            if( $registration->validate() ){
                if( $registration->register() ){
                    $this->user_id = $registration->user->id;
                    return $this->setToken();
                    //return array('success'=>true);
                }
            }else{
                foreach($registration->models AS $models){
                    if( $models->hasErrors() ){
                        Yii::$app->params['res-success'] = false;
                        return $models->getErrors();
                    }
                }
            }
        }
        Yii::$app->params['res-success'] = false;
        return false;
    }

    /**
     * 第三方登录
     *
     * POST /api/auth/oalogin
     *
     * @return array token
     */
    public function actionOalogin(){
        $oa = @$this->oa_http();
        $oa_type = '';
        if( isset($oa['oa_type']) ){
            if( $oa['oa_type']=='weixin' ){
                $oa_uid  = $oa['unionid'];
                $oa_type = $oa['oa_type'];
                $_POST['Password']['oa_type'] = $oa_type;
                $_POST['Password']['oa_uid']  = $oa_uid;
            }
            if( $oa['oa_type']=='weibo' ){
                $oa_uid  = $oa['uid'];
                $oa_type = $oa['oa_type'];
                $_POST['Password']['oa_type'] = $oa_type;
                $_POST['Password']['oa_uid']  = (string)$oa_uid;
            }
        }
        if( !$oa_type ){
            Yii::$app->params['res-success'] = false;
            return false;
        }

        $_POST['User']['username'] = 'UNI-' . substr(time(),-5)  . rand(100,999);
        $_POST['GroupUser']['group_id'] = 2; //user_group = 2[User]
        $_POST['Password']['newPassword']        = 'uni@x3y#99@2017';
        $_POST['Password']['newPasswordConfirm'] = 'uni@x3y#99@2017';
        $_POST['save'] = 1;
        $registration = new Registration();

        //uid exists
        $user = $registration->getOaUser($oa_uid, $oa_type);
        if( $user ){
            $this->user_id = $user->id;
            return $this->setToken();
        }

        $registration->enableOaField = true;
        $registration->enableUserApproval = false;
        if( $registration->submitted('save') ){
            if( $registration->validate() ){
                if( $registration->register() ){
                    $this->user_id = $registration->user->id;
                    return $this->setToken();
                }
            }else{
                foreach($registration->models AS $models){
                    if( $models->hasErrors() ){
                        Yii::$app->params['res-success'] = false;
                        return $models->getErrors();
                    }
                }
            }
        }
        Yii::$app->params['res-success'] = false;
        return false;
    }
    private function oa_http($url='', $method='', $post_data=array(), $headers=array()) {
        $type = $_POST['type'];
        $oa   = json_decode($_POST['ts'], true);
        if( $type=='weixin' ){
            $post_data['access_token'] = $oa['accessToken'];
            $post_data['openid']       = $oa['openid'];
            $url    = 'https://api.weixin.qq.com/sns/userinfo';
            $method = 'GET';
        }elseif( $type=='weibo' ){
            $post_data['access_token'] = $oa['accessToken'];
            $url    = 'https://api.weibo.com/oauth2/get_token_info';
            $method = 'POST';
        }else{
            return false;
        }

        $o = '';
        foreach($post_data as $k=>$v ){
            $o .= "$k=" . urlencode( $v ) . "&";
        }
        $postfields = substr($o, 0,-1);

        $ci = curl_init();
        /* Curl settings */
        curl_setopt($ci, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
        curl_setopt($ci, CURLOPT_USERAGENT, 'Sae T OAuth2 v0.1');
        curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, 30);
        curl_setopt($ci, CURLOPT_TIMEOUT, 30);
        curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);
        curl_setopt($ci, CURLOPT_ENCODING, "");
        curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, FALSE);
        if (version_compare(phpversion(), '5.4.0', '<')) {
            curl_setopt($ci, CURLOPT_SSL_VERIFYHOST, 1);
        } else {
            curl_setopt($ci, CURLOPT_SSL_VERIFYHOST, 2);
        }
        curl_setopt($ci, CURLOPT_HEADER, FALSE);

        switch ($method) {
            case 'POST':
                curl_setopt($ci, CURLOPT_POST, TRUE);
                if (!empty($postfields)) {
                    curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields);
                }
                break;
            case 'GET':
                curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE');
                if (!empty($postfields)) {
                    $url = "{$url}?{$postfields}";
                }
        }

        curl_setopt($ci, CURLOPT_URL, $url );
        curl_setopt($ci, CURLOPT_HTTPHEADER, $headers );
        curl_setopt($ci, CURLINFO_HEADER_OUT, TRUE );

        $response = curl_exec($ci);
        curl_close ($ci);

        $res = json_decode($response, true);
        $res['oa_type'] = $type;
        return $res;
    }

    /**
     * 找回密码：使用验证码找回
     *
     * POST /api/auth/repass
     *
     * string newPassword  新密码
     *
     * string newPasswordConfirm 重复密码
     *
     * string mphone   手机号（使用手机号注册时传值）
     *
     * string token    验证码
     *
     * @return array token
     */
    public function actionRepass(){
        $phone = Yii::$app->request->post('mphone');
        if( $userInvite = Invite::findOne(['email'=>$phone]) ){
            $userPassword = new \humhub\modules\user\models\Password();
            $userPassword->scenario = 'changePassword';
            if ($userPassword->load( ['Password' => Yii::$app->request->post()] ) && $userPassword->validate()) {
                if( preg_match('/^(1)[0-9]{10}$/', $phone) ){
                    $user = User::findOne(['mphone'=>$phone]);
                }else{
                    $user = User::findOne(['email'=>$phone]);
                }
                if( ! $user ){
                    throw new \yii\web\BadRequestHttpException('手机号或验证码无效');
                }
                if( $userInvite->checkToken(Yii::$app->request->post('token'), 'repass') ){
                    $userPassword->user_id = $user->id;
                    $userPassword->setPassword($userPassword->newPassword);
                    if( $userPassword->save() )
                        return true;
                }
            }
        }
        throw new \yii\web\BadRequestHttpException('手机号或验证码无效');
    }


    /**
     * 发送手机验证码,增加支持邮箱
     *
     * POST /api/auth/sphone
     *
     * post.Invite[email]  手机号 或 邮箱地址
     *
     * post.codetype 固定值: =1注册, =2密码找回, =3实名认证
     *
     * @return boolean
     */
    public function actionSphone(){
        // Self Invite
        $invite = new Invite();
        $invite->scenario = 'invite';
        if ($invite->load(Yii::$app->request->post()) ){
            if( ($si = $invite->selfInvite()) === true ){
                return true;
            }elseif( $si===false ){
                //default
            }else{
                Yii::$app->params['res-success'] = false;
                return array('email'=>array($si));
            }
        }
        Yii::$app->params['res-success'] = false;
        return $invite->getErrors();
    }

    /**
     * 验证手机验证码
     *
     * POST /api/auth/ctoken
     *
     * post.mphone 手机号
     *
     * post.token 验证码
     *
     * @return boolean
     */
    public function actionCtoken(){
        $token = Yii::$app->request->post('token');
        if( ! is_numeric($token) ){
            throw new \yii\web\BadRequestHttpException('手机号或验证码无效');
        }

        $phone = Yii::$app->request->post('mphone');
        $userInvite = Invite::findOne(['email'=>$phone]);
//type='ck'
        if( $userInvite ){
            //限制校验次数
            if( $userInvite->cklimit >= 3){
                throw new \yii\web\BadRequestHttpException('操作过于频繁，请稍后再试.');
            }
            if( $userInvite->token==$token ){
                return true;
            }else{
                //$userInvite->cklimit += 1; // !!! 无并发能力
                $userInvite->cklimit = new \yii\db\Expression('COALESCE(cklimit, 0) + 1');
                $userInvite->update();
                throw new \yii\web\BadRequestHttpException('手机号或验证码无效');
            }
        }
        throw new \yii\web\BadRequestHttpException('手机号或验证码无效');
    }

    /**
     * 退出登录
     *
     * GET /api/auth/logout
     *
     * @return boolean
     */
    public function actionLogout(){
        if( Yii::$app->user->logout() ){
            return true;
        }
        Yii::$app->params['res-success'] = false;
        return false;
    }

    /**
     * @inheritdoc
     */
    private function onAuthSuccess(\yii\authclient\BaseClient $authClient){
        $attributes = $authClient->getUserAttributes();

        // User already logged in - return true;
        if( ! Yii::$app->user->isGuest ){ //避免session开启的情况下重复登录
            AuthClientHelpers::storeAuthClientForUser($authClient, Yii::$app->user->getIdentity());
            return true;
        }

        // Login existing user
        $user = AuthClientHelpers::getUserByAuthClient($authClient);
        if( $user !== null ){
            $this->user_id = $user->id;
            return $this->login($user, $authClient);
        }
        return false;

        /* -------------------------------------------------------
        // Check if E-Mail is given
        if (!isset($attributes['email'])) {
            Yii::$app->session->setFlash('error', "Missing E-Mail Attribute from AuthClient.");
        }

        if (!isset($attributes['id'])) {
            Yii::$app->session->setFlash('error', "Missing ID AuthClient Attribute from AuthClient.");
        }

        // Check if e-mail is already taken
        if (User::findOne(['email' => $attributes['email']]) !== null) {
            Yii::$app->session->setFlash('error', Yii::t('UserModule.base', 'User with the same email already exists but isn\'t linked to you. Login using your email first to link it.'));
        }

        // Try automatically create user & login user
        $user = AuthClientHelpers::createUser($authClient);
        if ($user !== null) {
            return $this->login($user, $authClient);
        }

        // Make sure we normalized user attributes before put it in session (anonymous functions)
        $authClient->setNormalizeUserAttributeMap([]);

        // Store authclient in session - for registration controller
        Yii::$app->session->set('authClient', $authClient);

        // Start registration process
        return $this->redirect(['/user/registration']);
         */
    }

    /**
     * @inheritdoc
     */
    protected function login($user, $authClient){
        if ($user->status == User::STATUS_ENABLED) {
            $duration = 0;
            if ($authClient instanceof \humhub\modules\user\authclient\BaseFormAuth) {
                if ($authClient->login->rememberMe) {
                    $duration = Yii::$app->getModule('user')->loginRememberMeDuration;
                }
            }
            AuthClientHelpers::updateUser($authClient, $user);

            if (Yii::$app->user->login($user, $duration)) {
                $user->updateAttributes(['last_login' => new \yii\db\Expression('NOW()')]);
                Yii::$app->user->setCurrentAuthClient($authClient);
                $url = Yii::$app->user->returnUrl;
            }
        } elseif ($user->status == User::STATUS_DISABLED) {
            //Yii::$app->session->setFlash('error', 'Your account is disabled!');
            return 'Your account is disabled!';
        } elseif ($user->status == User::STATUS_NEED_APPROVAL) {
            return 'Your account is not approved yet!';
        } else {
            return 'Unknown user status!';
        }
        return true;
    }

    /**
     * 游客登录，返回指定用户token
     *
     * POST /api/auth/guest
     *
     * @return array token
     */
    public function actionGuest(){
        return false;
        if( ! $this->guest_uid ){
            Yii::$app->params['res-success'] = false;
            return false;
        }
        $user = User::findOne(['id' => $this->guest_uid]);
        $userId = $user->id;
        if( ! $userId ) return false;

        $ser[] = Yii::$app->request->userIP . Yii::$app->request->userAgent;
        $ser[] = uniqid();
        if( ! ($auth = ApiAuth::findOne(['user_id' => $userId])) ){
            $auth = new ApiAuth();
        }
        $auth->user_id      = $ser[] = $userId;
        $auth->client_id    = $ser[] = $this->client_id;
        $auth->expires_in   = $ser[] = 86400 * 30;
        $auth->expires_times= $ser[] = time() + $auth['expires_in'];
        $auth->active       = $ser[] = '1';
        //$auth->access_token = hash('sha256', serialize($ser), false);
        $auth->access_token = 'L2017f1f416C8e549a4349633fa9eB274560e87dfC9a39187236e56aaec4DfD0ddbc9d6A6B073e26b3aB71aaecc99fA24c482bbcffA0e9f668345c3428a5612B22d9c';
        if( $auth->save() ){
            return Array(
                'uid'         => $auth->user_id,
                'guid'        => $user->guid?$user->guid:'',
                'access_token'=> $auth->access_token,
                'expires_in'  => $auth->expires_in,
            );
        }
        Yii::$app->params['res-success'] = false;
        return false;
    }

    /**
     * @inheritdoc
     * set/get user token
     */
    private function setToken(){
        $userId = $this->user_id; //$userId = Yii::$app->user->id?Yii::$app->user->id:$this->user_id;
        if( ! $userId ) return false;
        $ser[] = Yii::$app->request->userIP . Yii::$app->request->userAgent;
        $ser[] = uniqid();
        if( ! ($auth = ApiAuth::findOne(['user_id' => $userId])) ){
            $auth = new ApiAuth();
        }
        $auth->user_id      = $ser[] = $userId;
        $auth->client_id    = $ser[] = $this->client_id;
        $auth->expires_in   = $ser[] = 86400 * 30;
        $auth->expires_times= $ser[] = time() + $auth['expires_in'];
        $auth->active       = $ser[] = '1';
        $auth->access_token = hash('sha256', serialize($ser), false);
        if( $auth->save() ){
            $user = User::findOne(['id' => $userId]);
            return Array(
                'uid'         => $auth->user_id,
                'guid'        => $user->guid?$user->guid:'',
                'u_v'         => $user->u_v,
                'u_real'      => $user->u_real,
                'profileimage'=> $user->getProfileImage()->getUrl(),
                'displayname' => $user->displayName,
                'access_token'=> $auth->access_token,
                'expires_in'  => $auth->expires_in,
                'rongyun'     => Invite::RegRongyun($user)?Invite::RegRongyun($user):'',
            );
        }
        Yii::$app->params['res-success'] = false;
        return false;
    }

}
